package service

import (
	myerror "CodeCover/internal/errors"
	"CodeCover/internal/models"
	"context"
	"time"

	"math/rand"
)

type UserRepository interface {
	Create(ctx context.Context, user *models.User) error
	FindByName(ctx context.Context, username string) (*models.User, error)
	GetUidByName(ctx context.Context, username string) (uint64, error)
	ApplyToken(ctx context.Context, username string) (string, error)
	IsValidToken(ctx context.Context, username string, token string) (bool, error)
}

type UserService struct {
	userRepo UserRepository
}

func NewUserService(userRepo UserRepository) *UserService {
	return &UserService{userRepo: userRepo}
}

func (s *UserService) generateUID() uint64 {
	randSource := rand.NewSource(time.Now().UnixNano())
	randGen := rand.New(randSource)

	// 时间戳部分（41位，毫秒级）
	timestamp := uint64(time.Now().UnixMilli()) & 0x1FFFFFFFFFF // 限制时间戳范围为 41 位
	// 随机数部分（23位）
	randomNum := randGen.Uint64() & 0x7FFFFF // 23位掩码
	// 组合64位UID：高41位时间戳 + 低23位随机数
	return (timestamp << 23) | randomNum
}

func (s *UserService) GetUidByName(ctx context.Context, name string) (uint64, error) {
	uid, err := s.userRepo.GetUidByName(ctx, name)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return 0, &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "UserService:GetUidByName() failed",
				OriginError: err,
				Metadata: map[string]any{
					"username": name,
				},
			}
		} else {
			return 0, &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "UserService:GetUidByName() failed",
				OriginError: err,
				Metadata: map[string]any{
					"username": name,
				},
			}
		}
	}

	return uid, nil
}
func (s *UserService) RegisterUser(ctx context.Context, user *models.User) error {

	user.Uid = s.generateUID()

	err := s.userRepo.Create(ctx, user)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "UserService:RegisterUser() failed",
				OriginError: err,
				Metadata: map[string]any{
					"user": user,
				},
			}
		} else {
			return &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "UserService:RegisterUser() failed",
				OriginError: err,
				Metadata: map[string]any{
					"user": user,
				},
			}
		}
	}
	return nil

}

func (s *UserService) Login(ctx context.Context, user *models.User) (*models.User, error) {

	existedUser, err := s.userRepo.FindByName(ctx, user.UserName)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return existedUser, &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "UserService:Login() failed",
				OriginError: err,
				Metadata: map[string]any{
					"user": user,
				},
			}
		} else {
			return existedUser, &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "UserService:Login() failed",
				OriginError: err,
				Metadata: map[string]any{
					"user": user,
				},
			}
		}
	}

	return existedUser, nil
}

func (s *UserService) ApplyToken(ctx context.Context, username string) (string, error) {
	token, err := s.userRepo.ApplyToken(ctx, username)
	if err != nil {
		if customErr, ok := err.(*myerror.CustomError); ok {
			return "", &myerror.CustomError{
				Code:        customErr.Code,
				Message:     "UserService:ApplyToken() failed",
				OriginError: err,
				Metadata: map[string]any{
					"username": username,
				},
			}
		} else {
			return "", &myerror.CustomError{
				Code:        myerror.DefaultFailure,
				Message:     "UserService:ApplyToken() failed",
				OriginError: err,
				Metadata: map[string]any{
					"username": username,
				},
			}
		}
	}
	return token, nil
}

func (s *UserService) IsValidToken(ctx context.Context, username string, token string) bool {
	ok, _ := s.userRepo.IsValidToken(ctx, username, token)
	return ok
}
